#/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Authors: Bruno Alves, n.º 6152; Neuza Figueira, n.º 6036

import socket
import fcntl
import struct
import string
import nmap

import IPSubnetCalc

import csv
import sqlite3

from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.units import inch
from reportlab.lib import colors

import os

class Port_Scan():
	'''Class that allows the detection of opened ports on multiple machines available in the current local network.''' 

	def get_ip_address(self, ifname):
		'''Method to obtain the ip address of a given network card.
		   @param ifname -> Network card designation.
		   @return the current IP address.'''
		return socket.inet_ntoa(fcntl.ioctl(socket.socket(socket.AF_INET, socket.SOCK_DGRAM),0x8915, struct.pack('256s', ifname[:15]))[20:24])


	def get_network_mask(self, ifname):
		'''Method to obtain the network mask of a given network card.
		   @param ifname -> Network card designation.
		   @return the network mask on CIDR notation.'''
		mask = socket.inet_ntoa(fcntl.ioctl(socket.socket(socket.AF_INET, socket.SOCK_DGRAM), 35099, struct.pack('256s', ifname))[20:24])
		temp = mask.split('.')
		temp2 = []
		i = 0
		
		for t in temp:
			temp2.append(int(bin(int(temp[i]))[2:]))
			i = i +1

		s = string.join(str(temp2))
		cidr_mask = s.count('1')

		return cidr_mask


	def portscan(self, network):
		'''Method to scan all the host on a given network.
		   @param network -> Network IP.
		   @return hosts_list -> List of all detected hosts.'''
		nm = nmap.PortScanner()

		nm.scan(hosts=network, arguments='-n -sP -PE -PA21,23,80,3389')
		hosts_list = [(x, nm[x]['status']['state']) for x in nm.all_hosts()]
		for host, status in hosts_list:
			#print('{0}:{1}'.format(host, status))
			pass

		return hosts_list


	def scan_host(self, target_host):
		'''Method to scan the open ports on a given host.
		   @param target_host -> IP of the host to scan.
		   @return port_list -> List of opended ports.'''
		nm_scan = nmap.PortScanner()
		nm_scan.scan(target_host)

		for proto in nm_scan[target_host].all_protocols():
			pass

		lport = nm_scan[target_host][proto].keys()
		lport.sort()

		port_list = [(port, nm_scan[target_host][proto][port]['state']) for port in lport]
		
		return port_list


	def create_csv_files(self, target_host, port_list):
		'''Method to create the csv file regarding the open ports of an host.
		   @param target_host -> IP of the host.
		   @param port_list -> List containing the open ports.'''
		print 'Creating CSV file...'
		outfiledir = os.getcwd() + "/CSV"

		if not os.path.exists(outfiledir):
			os.makedirs(outfiledir)

		name = outfiledir + '/Port_Scan_Results_' + target_host +'.csv'

		filename = open(name, 'wb')
		spamWriter = csv.writer(filename, delimiter=',')
		spamWriter.writerow(["PORT", "STATUS"])

		for host, status in port_list:
			spamWriter.writerow([host, status])      

		filename.close()
		print 'File successfully created on ' + name


	def create_database(self, target_host, port_list):
		'''Method to create the sqlite3 database regarding the open ports of an host.
		   @param target_host -> IP of the host.
		   @param port_list -> List containing the open ports.'''
		print 'Creating database...'
		outfiledir = os.getcwd() + "/DB"

		if not os.path.exists(outfiledir):
			os.makedirs(outfiledir)

		db_name = outfiledir + "/Port_Scan_Database_" + target_host + ".db"
		connection = sqlite3.connect(str(db_name))
		cursor = connection.cursor()

		cursor.execute('''drop table if exists data''')
		connection.commit()

		cursor.execute('''create table if not exists data (port_id TEXT PRIMARY KEY, state TEXT)''')

		for host, status in port_list:
			cmd = "INSERT INTO data (port_id, state) VALUES ('{0}','{1}');".format(host, status)
			cursor.execute(cmd)

		#cursor.execute("SELECT * FROM data")
		#rows = cursor.fetchall()
		#for row in rows:
		#	print row

		print 'Database successfully created on ' + db_name


	def create_pdf(self, target_host, port_list):
		'''Method to create the pdf file regarding the open ports of an host.
		   @param target_host -> IP of the host.
		   @param port_list -> List containing the open ports.'''
		print 'Creating PDF file...'
		styles = getSampleStyleSheet()

		outfilename = "Port_Scan_" + str(target_host) + ".pdf"
		outfiledir = os.getcwd() + "/PDF"
		outfilepath = os.path.join( outfiledir, outfilename )

		if not os.path.exists(outfiledir):
			os.makedirs(outfiledir)

		headerStyle = styles["Heading1"]

		doc = SimpleDocTemplate(outfilepath)
		Story = []
		style = styles["Normal"]
		title = "Port Scan of " + str(target_host)
		p = Paragraph(title, styles["Heading1"])

		Story.append(p)
		Story.append(Spacer(1,0.5*inch))

		data = [("Port", "Status")]
		
		for host, status in port_list:
			data.append([str(host), status])

		table = Table(data, colWidths=75, rowHeights=30)

		table.setStyle(TableStyle([('INNERGRID', (0,0), (-1, -1), 0.25, colors.black), 
                       ('BOX', (0, 0), (-1, -1), 0.25, colors.black), 
                       ('ALIGN',(0,0),(-1,-1),'CENTER'),
                       ('VALIGN',(0,0),(-1,-1),'MIDDLE')
                     ]))


		Story.append(table)
		doc.build(Story) 
		print 'File successfully created on ' + outfilepath

